package cn.spike.rockcc.service.impl;

import cn.spike.rockcc.domain.Course;
import cn.spike.rockcc.domain.CourseOrder;
import cn.spike.rockcc.domain.CourseOrderItem;
import cn.spike.rockcc.domain.PayOrder;
import cn.spike.rockcc.dto.CourseOrderDto;
import cn.spike.rockcc.dto.Order2Pay;
import cn.spike.rockcc.dto.RedisOrderDto;
import cn.spike.rockcc.errorenum.GlobalExceptionCode;
import cn.spike.rockcc.feign.CourseFeignClient;
import cn.spike.rockcc.mapper.CourseOrderMapper;
import cn.spike.rockcc.result.JSONResult;
import cn.spike.rockcc.service.ICourseOrderItemService;
import cn.spike.rockcc.service.ICourseOrderService;
import cn.spike.rockcc.util.AssertUtil;
import cn.spike.rockcc.util.CodeGenerateUtils;
import cn.spike.rockcc.vo.CourseDataVo;
import cn.spike.rockcc.vo.CourseItemVo;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.client.producer.TransactionSendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author spike
 * @since 2023-03-20
 */
@Service
public class CourseOrderServiceImpl extends ServiceImpl<CourseOrderMapper, CourseOrder> implements ICourseOrderService {

    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;

    @Autowired
    private CourseFeignClient courseFeignClient;

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @Autowired
    private ICourseOrderItemService courseOrderItemService;

    /**
     * 生成订单的业务方法
     * @param courseOrderDto
     * @return
     */
    @Override
    @Transactional
    public String createOrder(CourseOrderDto courseOrderDto) {
        Long loginId = 3L;  //TODO
        List<Long> courseIds = courseOrderDto.getCourseIds();
        String ids = courseIds.stream().map(String::valueOf).collect(Collectors.joining(","));
        System.out.println(ids);

        List<CourseItemVo> courseInfos = getcourseInfos(loginId, ids);

       /*course_order需要的信息
         total_mount - 支付总金额
         pay_mount - 支付金额
         user_id
         title - 订单标题
         */
        CourseOrder courseOrder = new CourseOrder();
        BigDecimal totalAmount = new BigDecimal(0);
        for (CourseItemVo courseInfo : courseInfos) {
            totalAmount = totalAmount.add(courseInfo.getCourseMarket().getPrice());
            courseInfo.getCourse().getName();
        }
        String courseNames = courseInfos.stream().map(CourseItemVo::getCourse).map(Course::getName).collect(Collectors.joining(","));
        courseOrder.setCreateTime(new Date());
        String orderNo = CodeGenerateUtils.generateOrderSn(loginId);
        courseOrder.setOrderNo(orderNo);
        courseOrder.setTotalAmount(totalAmount);
        courseOrder.setPayAmount(totalAmount);
        courseOrder.setDiscountAmount(new BigDecimal(0));
        courseOrder.setTotalCount(1);
        courseOrder.setStatusOrder(CourseOrder.ORDER_WAIT_PAY);
        courseOrder.setUserId(loginId);
        courseOrder.setTitle(CourseOrder.ORDER_TITLE+courseNames);
        courseOrder.setOrderType(CourseOrder.ORDER_TYPE_COMMON);
        courseOrder.setPayType(Integer.valueOf(courseOrderDto.getPayType()));

        courseInfos.forEach(courseItem -> {
            /*
                course_order_item需要的信息
                    amount - 课程的价格
                    count - 课程的数量
                    subtotal_amount - 小计费用
                    course_id - 课程id
                    course_name - 课程名字
                    course_pic - 课程封面
             */
            CourseOrderItem courseOrderItem = new CourseOrderItem();
            courseOrderItem.setOrderNo(orderNo);
            courseOrderItem.setAmount(courseItem.getCourseMarket().getPrice());
            courseOrderItem.setCount(1);
            courseOrderItem.setSubtotalAmount(courseItem.getCourseMarket().getPrice());
            courseOrderItem.setCreateTime(new Date());
            courseOrderItem.setCourseId(courseItem.getCourse().getId());
            courseOrderItem.setCourseName(courseItem.getCourse().getName());
            courseOrderItem.setCoursePic(courseItem.getCourse().getPic());

            courseOrder.getCourseOrderItems().add(courseOrderItem);
        });

        //封装生成pay订单需要的信息
        Order2Pay order2Pay = new Order2Pay();
        order2Pay.setAmount(courseOrder.getPayAmount());
        order2Pay.setOrderNo(orderNo);
        order2Pay.setPayType(Integer.parseInt(courseOrderDto.getPayType()));
        order2Pay.setUserId(loginId);
        order2Pay.setSubject(CourseOrder.ORDER_TITLE+courseNames);

        //投递事务消息
        Message<String> messgae = MessageBuilder.withPayload(JSON.toJSONString(order2Pay)).build();
        TransactionSendResult transactionSendResult = rocketMQTemplate.sendMessageInTransaction(
                "tx-order",
                "order-topic:order-tags",
                messgae,
                courseOrder
        );
        Boolean boo = transactionSendResult.getSendStatus() == SendStatus.SEND_OK;
        AssertUtil.isTrue(boo,GlobalExceptionCode.ORDER_MQ_SEND_EXCEPTION);
        Message<String> orderNoMessage = MessageBuilder.withPayload(orderNo).build();
        //syncSend(String destination, Message<?> message, long timeout, int delayLevel)
        SendResult sendResult = rocketMQTemplate.syncSend(
                    "order-delay-topic:order-delay-tags",
                orderNoMessage,
                3000,
                15
        );
        Boolean boo2 = sendResult.getSendStatus() == SendStatus.SEND_OK;
        AssertUtil.isTrue(boo2,GlobalExceptionCode.ORDER_MQ_SEND_EXCEPTION);
        redisTemplate.delete(loginId + ":" + ids);
        return orderNo;
    }


    @Transactional
    public void createCourseOrder(CourseOrder courseOrder){
        super.insert(courseOrder);
        List<CourseOrderItem> courseOrderItems = courseOrder.getCourseOrderItems();
        courseOrderItems.forEach(item->item.setOrderId(courseOrder.getId()));
        courseOrderItemService.insertBatch(courseOrderItems);
    }


    @Override
    @Transactional
    public void updateCourseOrderByPayOrder(PayOrder payOrder) {
        Wrapper<CourseOrder> wrapper = new EntityWrapper<>();
        wrapper.eq("order_no",payOrder.getOrderNo());
        CourseOrder courseOrder = super.selectOne(wrapper);
        if(payOrder.getPayStatus().equals(courseOrder.getStatusOrder()))return;

        courseOrder.setStatusOrder(payOrder.getPayStatus());
        if(payOrder.getPayStatus().equals(PayOrder.PAY_CANCEL))courseOrder.setStatusOrder(CourseOrder.ORDER_PAY_FAIL);

        courseOrder.setUpdateTime(new Date());
        Wrapper<CourseOrderItem> itemWrapper = new EntityWrapper<>();
        itemWrapper.eq("order_id",courseOrder.getId());
        List<CourseOrderItem> courseOrderItems = courseOrderItemService.selectList(itemWrapper);
        courseOrderItems.forEach(item->{
            item.setUpdateTime(new Date());
        });
        courseOrderItemService.updateBatchById(courseOrderItems);
    }

    @Override
    public CourseOrder selectByOrderNo(String orderNo) {
        Wrapper<CourseOrder> wrapper = new EntityWrapper<>();
        wrapper.eq("order_no",orderNo);
        return super.selectOne(wrapper);
    }

    @Override
    @Transactional
    public void orderTimeOut(CourseOrder courseOrder) {
        Wrapper<CourseOrderItem> wrapper = new EntityWrapper<>();
        wrapper.eq("order_id",courseOrder.getId());
        List<CourseOrderItem> courseOrderItems = courseOrderItemService.selectList(wrapper);
        courseOrderItems.forEach(item->{
            item.setUpdateTime(new Date());
        });
        courseOrderItemService.updateBatchById(courseOrderItems);
        courseOrder.setStatusOrder(CourseOrder.ORDER_TIMEOUT_CANCEL);
        courseOrder.setUpdateTime(new Date());
        super.updateById(courseOrder);
    }

    /**
     * 查找当前用户的所有订单
     * @return
     */
    @Override
    public List<CourseOrder> selectOrderByUser() {
        Long userId = 3L; //TODO
        Wrapper<CourseOrder> wrapper = new EntityWrapper<>();
        wrapper.eq("user_id",userId);
        List<CourseOrder> courseOrders = super.selectList(wrapper);
        for (CourseOrder courseOrder : courseOrders) {
            Wrapper<CourseOrderItem> itemWrapper = new EntityWrapper<>();
            itemWrapper.eq("order_id",courseOrder.getId());
            courseOrder.setItems(courseOrderItemService.selectList(itemWrapper));
        }
        return courseOrders;
    }

    /**
     * 取消订单的业务
     * @param orderNo
     */
    @Override
    @Transactional
    public void cancelOrder(String orderNo) {
        //用orderNo查找出当前订单
        Wrapper<CourseOrder> wrapper = new EntityWrapper<>();
        wrapper.eq("order_no",orderNo);
        CourseOrder courseOrder = super.selectOne(wrapper);
        //如果用订单编号查找不出订单 - 说明订单编号有误
        AssertUtil.isNotNull(courseOrder,GlobalExceptionCode.NOT_HAVE_ORDER_EXCEPTION);
        //如果订单状态不是待处理 - 直接返回
        if(!courseOrder.getStatusOrder().equals(CourseOrder.ORDER_WAIT_PAY)) return;
        //修改状态
        courseOrder.setStatusOrder(CourseOrder.ORDER_USER_CANCEL);
        courseOrder.setUpdateTime(new Date());
        //查找出订单明细
        Wrapper<CourseOrderItem> itemWrapper = new EntityWrapper<>();
        itemWrapper.eq("order_id",courseOrder.getId());
        List<CourseOrderItem> courseOrderItems = courseOrderItemService.selectList(itemWrapper);
        //添加订单明细的修改日期
        courseOrderItems.forEach(courseOrderItem -> courseOrderItem.setUpdateTime(new Date()));
        courseOrder.setCourseOrderItems(courseOrderItems);
        //投递mq消息 - 投递给pay服务
        //String txProducerGroup, String destination, Message<?> message, Object arg
        Message<String> message = MessageBuilder.withPayload(orderNo).build();
        TransactionSendResult transactionSendResult = rocketMQTemplate.sendMessageInTransaction(
                "tx-cancelOrder",
                "orderCancel-topic:orderCancel-tags",
                message,
                courseOrder
        );
        boolean sendResult = transactionSendResult.getSendStatus() == SendStatus.SEND_OK;
        AssertUtil.isTrue(sendResult,GlobalExceptionCode.ORDER_MQ_SEND_EXCEPTION);
    }

    @Override
    @Transactional
    public void updateOrderAndItems(CourseOrder courseOrder) {
        List<CourseOrderItem> courseOrderItems = courseOrder.getCourseOrderItems();
        courseOrderItemService.updateBatchById(courseOrderItems);
        super.updateById(courseOrder);
    }

    @Override
    public String killPlaceOrder(CourseOrderDto courseOrderDto) {
        Object o = redisTemplate.opsForValue().get(courseOrderDto.getOrderNo());
        AssertUtil.isNotNull(o,GlobalExceptionCode.REDIS_ORDER_NOT_FOUND);
        RedisOrderDto redisOrderDto = (RedisOrderDto) o;
        String ids = redisOrderDto.getCourseId().toString();
        Long loginId = redisOrderDto.getUserId();  //TODO

        List<CourseItemVo> courseInfos = getcourseInfos(loginId, ids);

       /*course_order需要的信息
         total_mount - 支付总金额
         pay_mount - 支付金额
         user_id
         title - 订单标题
         */
        CourseOrder courseOrder = new CourseOrder();
        BigDecimal totalAmount = new BigDecimal(0);
        for (CourseItemVo courseInfo : courseInfos) {
            totalAmount = totalAmount.add(redisOrderDto.getAmount());
            courseInfo.getCourse().getName();
        }
        String courseNames = courseInfos.stream().map(CourseItemVo::getCourse).map(Course::getName).collect(Collectors.joining(","));
        courseOrder.setCreateTime(new Date());
        String orderNo = redisOrderDto.getOrderNo();
        courseOrder.setOrderNo(orderNo);
        courseOrder.setTotalAmount(totalAmount);
        courseOrder.setPayAmount(totalAmount);
        courseOrder.setDiscountAmount(new BigDecimal(0));
        courseOrder.setTotalCount(1);
        courseOrder.setStatusOrder(CourseOrder.ORDER_WAIT_PAY);
        courseOrder.setUserId(loginId);
        courseOrder.setOrderType(CourseOrder.ORDER_TYPE_KILL);
        courseOrder.setTitle(CourseOrder.KILL_ORDER_TITLE+courseNames);
        courseOrder.setPayType(Integer.valueOf(courseOrderDto.getPayType()));

        for (CourseItemVo courseItem : courseInfos) {
            /*
                course_order_item需要的信息
                    amount - 课程的价格
                    count - 课程的数量
                    subtotal_amount - 小计费用
                    course_id - 课程id
                    course_name - 课程名字
                    course_pic - 课程封面
             */
            CourseOrderItem courseOrderItem = new CourseOrderItem();
            courseOrderItem.setOrderNo(orderNo);
            courseOrderItem.setAmount(courseItem.getCourseMarket().getPrice());
            courseOrderItem.setCount(1);
            courseOrderItem.setSubtotalAmount(redisOrderDto.getAmount());
            courseOrderItem.setCreateTime(new Date());
            courseOrderItem.setCourseId(courseItem.getCourse().getId());
            courseOrderItem.setCourseName(courseItem.getCourse().getName());
            courseOrderItem.setCoursePic(courseItem.getCourse().getPic());
            courseOrderItem.setKillCourseId(redisOrderDto.getKillCourseId());

            courseOrder.getCourseOrderItems().add(courseOrderItem);

        }

        //封装生成pay订单需要的信息
        Order2Pay order2Pay = new Order2Pay();
        order2Pay.setAmount(courseOrder.getPayAmount());
        order2Pay.setOrderNo(orderNo);
        order2Pay.setPayType(Integer.parseInt(courseOrderDto.getPayType()));
        order2Pay.setUserId(loginId);
        order2Pay.setSubject(CourseOrder.KILL_ORDER_TITLE+courseNames);

        //投递事务消息
        Message<String> messgae = MessageBuilder.withPayload(JSON.toJSONString(order2Pay)).build();
        TransactionSendResult transactionSendResult = rocketMQTemplate.sendMessageInTransaction(
                "tx-order",
                "order-topic:order-tags",
                messgae,
                courseOrder
        );
        Boolean boo = transactionSendResult.getSendStatus() == SendStatus.SEND_OK;
        AssertUtil.isTrue(boo,GlobalExceptionCode.ORDER_MQ_SEND_EXCEPTION);
        Message<String> orderNoMessage = MessageBuilder.withPayload(orderNo).build();
        //syncSend(String destination, Message<?> message, long timeout, int delayLevel)
        SendResult sendResult = rocketMQTemplate.syncSend(
                "order-delay-topic:order-delay-tags",
                orderNoMessage,
                3000,
                15
        );
        Boolean boo2 = sendResult.getSendStatus() == SendStatus.SEND_OK;
        AssertUtil.isTrue(boo2,GlobalExceptionCode.ORDER_MQ_SEND_EXCEPTION);
        redisTemplate.delete(loginId + ":" + ids);
        redisTemplate.delete(orderNo);
        return orderNo;
    }

    private  List<CourseItemVo> getcourseInfos(Long loginId,String ids){
        Object tokenInRedis = redisTemplate.opsForValue().get(loginId + ":" + ids);
        //AssertUtil.isNotNull(tokenInRedis, GlobalExceptionCode.ORDER_RETAKE_EXCEPTION);

        JSONResult jsonResult = courseFeignClient.orderdata(ids);
        AssertUtil.isTrue(jsonResult.isSuccess(),GlobalExceptionCode.COURSE_EXCEPTION);
        Object resultData = jsonResult.getData();
        CourseDataVo courseDataVo = JSON.parseObject(JSON.toJSONString(resultData), CourseDataVo.class);
        List<CourseItemVo> courseInfos = courseDataVo.getCourseInfos();
        return courseInfos;
    }
}
